<#if po??>
package ${serviceImplPackage};

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.odianyun.project.query.PageQueryArgs;
import com.odianyun.project.query.QueryArgs;

<#if po.relManyList?size gt 0>
import org.apache.commons.collections4.ListUtils;
</#if>
import com.odianyun.project.support.base.service.OdyEntityService;
<#if po.exportable || po.tableFields?size gt 0 || po.relOneList?size gt 0 || po.relManyList?size gt 0>
import com.odianyun.db.mybatis.EntityQueryParam;
</#if>
<#if po.exportable || po.tableFields?size gt 0>
import com.odianyun.db.mybatis.AbstractQueryFilterParam;
import com.odianyun.project.query.QueryParamBuilder;
</#if>
<#if po.relOneList?size gt 0 || po.relManyList?size gt 0>
import com.odianyun.project.support.base.OdyHelper;
import com.odianyun.project.base.IEntity;
import com.odianyun.db.mybatis.BatchInsertParam;
import com.odianyun.project.support.base.db.Q;
import com.odianyun.project.support.base.db.EQ;
import com.odianyun.project.support.base.db.BU;
import com.odianyun.project.support.base.db.UF;
</#if>

import ${mapperPackage}.${po.name}Mapper;
import ${poPackage}.${po.name}PO;
import ${voPackage}.${po.name}VO;
<#if po.relOneList?size gt 0 || po.relManyList?size gt 0>
import ${dtoPackage}.${po.name}DTO;
</#if>
import ${servicePackage}.${po.name}Service;
<#list po.relOneList as rel>
import ${poPackage}.${rel.name}PO;
import ${voPackage}.${rel.name}VO;
import ${dtoPackage}.${rel.name}DTO;
import ${mapperPackage}.${rel.name}Mapper;
<#if rel.mainField.requireTypeImport>
import ${rel.mainField.typeFullName};
</#if>
</#list>
<#list po.relManyList as rel>
import ${poPackage}.${rel.name}PO;
import ${voPackage}.${rel.name}VO;
import ${dtoPackage}.${rel.name}DTO;
import ${mapperPackage}.${rel.name}Mapper;
<#if rel.mainField.requireTypeImport>
import ${rel.mainField.typeFullName};
</#if>
</#list>
<#if po.relOneList?size gt 0 || po.relManyList?size gt 0>
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
</#if>
import java.util.List;

@Service
public class ${po.name}ServiceImpl extends OdyEntityService<${po.name}PO, ${po.name}VO, PageQueryArgs, QueryArgs, ${po.name}Mapper> implements ${po.name}Service {
    @Resource
    private ${po.name}Mapper mapper;
    <#list po.relOneList as rel>
    @Resource
    private ${rel.name}Mapper ${rel.uncapName}Mapper;
    </#list>
    <#list po.relManyList as rel>
    @Resource
    private ${rel.name}Mapper ${rel.uncapName}Mapper;
    </#list>
    
    @Override
    protected ${po.name}Mapper getMapper() {
        return mapper;
    }

    <#if po.exportable>
    <#-- 导出查询 -->
    @Override
    protected AbstractQueryFilterParam<?> toQueryFilterParam(QueryArgs args) {
        <#-- 主表 -->
        <#assign hasAnySearchFields = false>
        <#list po.searchFields as field>
            <#if field.modelName == po.name>
                <#assign hasAnySearchFields = true>
                <#break>
            </#if>
        </#list>
        <#if hasAnySearchFields>
        String[] mainSearchFields = new String[] {<#list po.searchFields as field><#if field.modelName == po.name>"${field.name}"<#sep>, </#sep></#if></#list>};
        </#if>
        EntityQueryParam main = new QueryParamBuilder(args<#if hasAnySearchFields>, mainSearchFields</#if>)
                .buildParam(new EQ(${po.name}PO.class, "main"));
        main.select("id")<#list po.exportFields as field><#if field.modelName == po.name>.select("${field.name}"<#if field.name != field.relName>, "${field.relName}"</#if>)</#if></#list>;
        <#-- 关联一对一 -->
        <#-- 以下设置hasAnySearchFields和hasAnyExportFields两个变量 -->
        <#list po.relOneList as rel>
            <#assign hasAnySearchFields = false>
            <#assign hasAnyExportFields = false>
            <#list po.searchFields as field>
                <#if field.modelName == rel.name>
                    <#assign hasAnySearchFields = true>
                    <#break>
                </#if>
            </#list>
            <#list po.exportFields as field>
                <#if field.modelName == rel.name>
                    <#assign hasAnyExportFields = true>
                    <#break>
                </#if>
            </#list>
        <#if hasAnySearchFields || hasAnyExportFields>
            <#if hasAnySearchFields>
        String[] ${rel.uncapName}SearchFields = new String[] {<#list po.searchFields as field><#if field.modelName == rel.name>"${field.relName}"<#sep>, </#sep></#if></#list>};
            </#if>
        EntityQueryParam ${rel.uncapName}Param = new QueryParamBuilder(args<#if hasAnySearchFields>, ${rel.uncapName}SearchFields</#if>)<#list po.searchFields as field><#if field.name != field.relName >
                .rename("${field.relName}", "${field.name}")</#if></#list>
                <#if !hasAnyExportFields>.withEmptyFilterToNull()</#if>.buildParam(new EQ(${rel.name}PO.class, "${rel.uncapName}"));
            <#if hasAnyExportFields>
        ${rel.uncapName}Param<#list po.exportFields as field><#if field.modelName == rel.name>.select("${field.name}"<#if field.name != field.relName>, "${field.relName}</#if>")</#if></#list>;
            </#if>
        if (${rel.uncapName}Param != null) {
            main.<#if hasAnyExportFields>join<#else>leftJoin</#if>(${rel.uncapName}Param).on("${rel.mainField.name}", "${rel.relField.name}");
        }
        </#if>
        </#list>
        <#-- 关联一对多 -->
        <#-- 以下设置hasAnySearchFields和hasAnyExportFields两个变量 -->
        <#list po.relManyList as rel>
            <#assign hasAnySearchFields = false>
            <#assign hasAnyExportFields = false>
            <#list po.searchFields as field>
                <#if field.modelName == rel.name>
                    <#assign hasAnySearchFields = true>
                    <#break>
                </#if>
            </#list>
            <#list po.exportFields as field>
                <#if field.modelName == rel.name>
                    <#assign hasAnyExportFields = true>
                    <#break>
                </#if>
            </#list>
        <#if hasAnySearchFields || hasAnyExportFields>
            <#if hasAnySearchFields>
        String[] ${rel.uncapName}SearchFields = new String[] {<#list po.searchFields as field><#if field.modelName == rel.name>"${field.relName}"<#sep>, </#sep></#if></#list>};
            </#if>
        EntityQueryParam ${rel.uncapName}Param = new QueryParamBuilder(args<#if hasAnySearchFields>, ${rel.uncapName}SearchFields</#if>)<#list po.searchFields as field><#if field.name != field.relName>
                .rename("${field.relName}", "${field.name}")</#if></#list>
                <#if !hasAnyExportFields>.withEmptyFilterToNull()</#if>.buildParam(new EQ(${rel.name}PO.class, "${rel.uncapName}"));
            <#if hasAnyExportFields>
        ${rel.uncapName}Param<#list po.exportFields as field><#if field.modelName == rel.name>.select("${field.name}"<#if field.name == field.relName>, "${field.relName}"</#if>)</#if></#list>;
            </#if>
        if (${rel.uncapName}Param != null) {
            main.<#if hasAnyExportFields>join<#else>exists</#if>(${rel.uncapName}Param).on("${rel.mainField.name}", "${rel.relField.name}");
        }
        </#if>
        </#list>

        return main;
    }
    </#if>

    <#if po.tableFields?size gt 0>
    <#-- 列表查询 -->
    @Override
    protected AbstractQueryFilterParam<?> toQueryFilterParam(PageQueryArgs args) {
        <#-- 主表 -->
        <#assign hasAnySearchFields = false>
        <#list po.searchFields as field>
            <#if field.modelName == po.name>
                <#assign hasAnySearchFields = true>
                <#break>
            </#if>
        </#list>
        <#if hasAnySearchFields>
        String[] mainSearchFields = new String[] {<#list po.searchFields as field><#if field.modelName == po.name>"${field.name}"<#sep>, </#sep></#if></#list>};
        </#if>
        EntityQueryParam main = new QueryParamBuilder(args<#if hasAnySearchFields>, mainSearchFields</#if>)
                .buildParam(new EQ(${po.name}PO.class, "main"));
        main.select("id")<#list po.tableFields as field><#if field.modelName == po.name>.select("${field.name}"<#if field.name == field.relName>, "${field.relName}"</#if>)</#if></#list>;
        <#-- 关联一对一 -->
        <#-- 以下设置hasAnySearchFields和hasAnyTableFields两个变量 -->
        <#list po.relOneList as rel>
            <#assign hasAnySearchFields = false>
            <#assign hasAnyTableFields = false>
            <#list po.searchFields as field>
                <#if field.modelName == rel.name>
                    <#assign hasAnySearchFields = true>
                    <#break>
                </#if>
            </#list>
            <#list po.tableFields as field>
                <#if field.modelName == rel.name>
                    <#assign hasAnyTableFields = true>
                    <#break>
                </#if>
            </#list>
        <#if hasAnySearchFields || hasAnyTableFields>
            <#if hasAnySearchFields>
        String[] ${rel.uncapName}SearchFields = new String[] {<#list po.searchFields as field><#if field.modelName == rel.name>"${field.relName}"<#sep>, </#sep></#if></#list>};
            </#if>
        EntityQueryParam ${rel.uncapName}Param = new QueryParamBuilder(args<#if hasAnySearchFields>, ${rel.uncapName}SearchFields</#if>)
            <#list po.searchFields as field><#if field.name != field.relName >.rename("${field.relName}", "${field.name}")</#if></#list>
            <#if !hasAnyTableFields>.withEmptyFilterToNull()</#if>.buildParam(new EQ(${rel.name}PO.class, "${rel.uncapName}"));
            <#if hasAnyTableFields>
        ${rel.uncapName}Param<#list po.tableFields as field><#if field.modelName == rel.name>.select("${field.name}"<#if field.name == field.relName>, "${field.relName}"</#if>)</#if></#list>;
            </#if>
        if (${rel.uncapName}Param != null) {
            main.<#if hasAnyTableFields>join<#else>leftJoin</#if>(${rel.uncapName}Param).on("${rel.mainField.name}", "${rel.relField.name}");
        }
        </#if>
        </#list>
        <#-- 关联一对多 -->
        <#-- 以下设置hasAnySearchFields和hasAnyTableFields两个变量 -->
        <#list po.relManyList as rel>
            <#assign hasAnySearchFields = false>
            <#assign hasAnyTableFields = false>
            <#list po.searchFields as field>
                <#if field.modelName == rel.name>
                    <#assign hasAnySearchFields = true>
                    <#break>
                </#if>
            </#list>
            <#list po.tableFields as field>
                <#if field.modelName == rel.name>
                    <#assign hasAnyTableFields = true>
                    <#break>
                </#if>
            </#list>
        <#if hasAnySearchFields || hasAnyTableFields>
            <#if hasAnySearchFields>
        String[] ${rel.uncapName}SearchFields = new String[] {<#list po.searchFields as field><#if field.modelName == rel.name>"${field.relName}"<#sep>, </#sep></#if></#list>};
            </#if>
        EntityQueryParam ${rel.uncapName}Param = new QueryParamBuilder(args<#if hasAnySearchFields>, ${rel.uncapName}SearchFields</#if>)
            <#list po.searchFields as field><#if field.name != field.relName >.rename("${field.relName}", "${field.name}")</#if></#list>
            <#if !hasAnyTableFields>.withEmptyFilterToNull()</#if>.buildParam(new EQ(${rel.name}PO.class, "${rel.uncapName}"));
            <#if hasAnyTableFields>
        ${rel.uncapName}Param<#list po.tableFields as field><#if field.modelName == rel.name>.select("${field.name}"<#if field.name == field.relName>, "${field.relName}"</#if>)</#if></#list>;
            </#if>
        if (${rel.uncapName}Param != null) {
            main.<#if hasAnyTableFields>join<#else>exists</#if>(${rel.uncapName}Param).on("${rel.mainField.name}", "${rel.relField.name}");
        }
        </#if>
        </#list>

        return main;
    }
    </#if>
    <#list po.relOneList as rel>

    @Override
    public ${rel.name}VO get${rel.name}(${rel.mainField.typeName} ${rel.mainField.name}) {
        return ${rel.uncapName}Mapper.getForEntity(new EQ(${rel.name}VO.class).selectAll().eq("${rel.relField.name}", ${rel.mainField.name}));
    }
    </#list>
    <#list po.relManyList as rel>

    @Override
    public List<${rel.name}VO> list${rel.name}(${rel.mainField.typeName} ${rel.mainField.name}) {
        return ${rel.uncapName}Mapper.listForEntity(new EQ(${rel.name}VO.class).selectAll().eq("${rel.relField.name}", ${rel.mainField.name}));
    }
    </#list>
    <#-- 编辑 start -->
    <#if po.relOneList?size gt 0 || po.relManyList?size gt 0>
    <#assign hasAllAnyEditFields = false>
    <#list po.relOneList as rel>
        <#if rel.editable>
            <#assign hasAllAnyEditFields = true>
            <#break>
        </#if>
        <#if hasAllAnyEditFields><#break></#if>
    </#list>
    <#list po.relManyList as rel>
        <#if rel.editable>
            <#assign hasAllAnyEditFields = true>
            <#break>
        </#if>
        <#if hasAllAnyEditFields><#break></#if>
    </#list>
    <#if hasAllAnyEditFields>

    @Override
    protected void afterAdd(${po.name}PO po, IEntity iEntity) throws Exception {
        super.afterAdd(po, iEntity);
        ${po.name}DTO dto = iEntity.convertTo(${po.name}DTO.class);
        <#list po.relOneList as rel>
            <#if rel.editable>
        ${rel.name}DTO ${rel.uncapName}DTO = dto.get${rel.name}();
        if (${rel.uncapName}DTO != null) {
            ${rel.uncapName}DTO.set${rel.relField.capName}(dto.get${rel.mainField.capName}());
            ${rel.uncapName}Mapper.add(new InsertParam(${rel.uncapName}DTO.convertTo(${rel.name}PO.class));
        }
            </#if>
        </#list>

        <#list po.relManyList as rel>
            <#if rel.editable>
        List<${rel.name}DTO> ${rel.uncapName}List = dto.get${rel.name}List();
        if (CollectionUtils.isNotEmpty(${rel.uncapName}List)) {
            for (${rel.name}DTO ${rel.uncapName} : ${rel.uncapName}List) {
                ${rel.uncapName}.set${rel.relField.capName}(dto.get${rel.mainField.capName}());
            }
            ${rel.uncapName}Mapper.batchAddByJdbc(new BatchInsertParam(IEntity.convertToList(${rel.uncapName}List, ${rel.name}PO.class)));
        }
            </#if>
        </#list>
    }

    @Override
    protected void afterUpdate(${po.name}PO po, IEntity iEntity) throws Exception {
        super.afterUpdate(po, iEntity);
        ${po.name}DTO dto = iEntity.convertTo(${po.name}DTO.class);
        <#list po.relOneList as rel>
            <#if rel.editable>
        ${rel.name}DTO ${rel.uncapName}DTO = dto.get${rel.name}();
        if (${rel.uncapName}DTO != null) {
            if (${rel.uncapName}DTO.getId() != null) {
                ${rel.uncapName}Mapper.update(new U(${rel.uncapName}.convertTo(${rel.name}PO.class)));
            } else {
                ${rel.uncapName}DTO.set${rel.relField.capName}(dto.get${rel.mainField.capName}());
                ${rel.uncapName}Mapper.add(new InsertParam(${rel.uncapName}DTO.convertTo(${rel.name}PO.class)));
            }
        } else {
            ${rel.uncapName}Mapper.updateField(new UF(OdyHelper.IS_DELETED, OdyHelper.DELETE_YES).eq("${rel.relField.name}", dto.get${rel.mainField.capName}()));
        }
            </#if>
        </#list>

        <#list po.relManyList as rel>
            <#if rel.editable>
        List<Long> stale${rel.name}Ids = ${rel.uncapName}Mapper.listForLong(new Q("id").eq("${rel.relField.name}", dto.get${rel.mainField.capName}()));
        List<Long> fresh${rel.name}Ids = Lists.newArrayList();

        List<${rel.name}DTO> rel${rel.name}List = dto.get${rel.name}List();
        if (CollectionUtils.isNotEmpty(rel${rel.name}List)) {
            List<${rel.name}PO> preInsertRelList = Lists.newArrayList();
            List<${rel.name}PO> preUpdateRelList = Lists.newArrayList();

            for (${rel.name}DTO rel : rel${rel.name}List) {
                if (rel.getId() != null) {
                    fresh${rel.name}Ids.add(rel.getId());
                    preUpdateRelList.add(rel.convertTo(${rel.name}PO.class));
                } else {
                    rel.set${rel.relField.capName}(dto.get${rel.mainField.capName}());
                    preInsertRelList.add(rel.convertTo(${rel.name}PO.class));
                }
            }
            if (CollectionUtils.isNotEmpty(preInsertRelList)) {
                ${rel.uncapName}Mapper.batchAddByJdbc(new BatchInsertParam(preInsertRelList));
            }
            if (CollectionUtils.isNotEmpty(preUpdateRelList)) {
                ${rel.uncapName}Mapper.batchUpdateByJdbc(new BU(preUpdateRelList).eqField("id"));
            }
        }
        List<Long> preDelete${rel.name}List = ListUtils.removeAll(stale${rel.name}Ids, fresh${rel.name}Ids);
        if (CollectionUtils.isNotEmpty(preDelete${rel.name}List)) {
            ${rel.uncapName}Mapper.updateField(new UF(OdyHelper.IS_DELETED, OdyHelper.DELETE_YES).in("id", preDelete${rel.name}List));
        }
            </#if>
        </#list>
    }
    </#if>
    <#-- 编辑 end -->
    <#-- 批量导入 start -->
    <#if po.importable>
    <#assign hasAllAnyImportFields = false>
    <#list po.relOneList as rel>
        <#list po.importFields as field>
            <#if field.modelName == rel.name>
                <#assign hasAllAnyImportFields = true>
                <#break>
            </#if>
        </#list>
        <#if hasAllAnyImportFields><#break></#if>
    </#list>
    <#list po.relManyList as rel>
        <#list po.importFields as field>
            <#if field.modelName == rel.name>
                <#assign manyMainField = rel.mainField>
                <#assign hasAllAnyImportFields = true>
                <#break>
            </#if>
        </#list>
        <#if hasAllAnyImportFields><#break></#if>
    </#list>
    <#if hasAllAnyImportFields>

    @Override
    protected void afterBatchAdd(List<? extends ${po.name}PO> elist, List<? extends IEntity> ulist) throws Exception {
        super.afterBatchAdd(elist, ulist);
        <#list po.relOneList as rel>
            <#assign hasAnyImportFields = false>
            <#list po.importFields as field>
                <#if field.modelName == rel.name>
                    <#assign hasAnyImportFields = true>
                    <#break>
                </#if>
            </#list>
            <#if hasAnyImportFields>
        List<${rel.name}PO> ${rel.uncapName}List = Lists.newArrayListWithExpectedSize(ulist.size());
            </#if>
        </#list>
        <#list po.relManyList as rel>
            <#assign hasAnyImportFields = false>
            <#list po.importFields as field>
                <#if field.modelName == rel.name>
                    <#assign hasAnyImportFields = true>
                    <#break>
                </#if>
            </#list>
            <#if hasAnyImportFields>
        List<${rel.name}PO> ${rel.uncapName}AllList = Lists.newArrayList();
            </#if>
        </#list>
        for (IEntity iEntity : ulist) {
            ${po.name}DTO dto = (${po.name}DTO) iEntity;
            <#list po.relOneList as rel>
                <#assign hasAnyImportFields = false>
                <#list po.importFields as field>
                    <#if field.modelName == rel.name>
                        <#assign hasAnyImportFields = true>
                        <#break>
                    </#if>
                </#list>
                <#if hasAnyImportFields>
            ${rel.name}DTO ${rel.uncapName} = dto.get${rel.name}();
            if (${rel.uncapName} != null) {
                ${rel.uncapName}.set${rel.relField.capName}(dto.get${rel.mainField.capName}());
                ${rel.uncapName}List.add(${rel.uncapName}.convertTo(${rel.name}PO.class));
            }
                </#if>
            </#list>
            <#list po.relManyList as rel>
                <#assign hasAnyImportFields = false>
                <#list po.importFields as field>
                    <#if field.modelName == rel.name>
                        <#assign hasAnyImportFields = true>
                        <#break>
                    </#if>
                </#list>
                <#if hasAnyImportFields>
            List<${rel.name}DTO> ${rel.uncapName}List = dto.get${rel.name}List();
            if (CollectionUtils.isNotEmpty(${rel.uncapName}List)) {
                for (${rel.name}DTO ${rel.uncapName} : ${rel.uncapName}List) {
                    ${rel.uncapName}.set${rel.relField.capName}(dto.get${rel.mainField.capName}());
                }
                ${rel.uncapName}AllList.addAll(IEntity.convertToList(${rel.uncapName}List, ${rel.name}PO.class));
            }
                </#if>
            </#list>
        }
        <#list po.relOneList as rel>
            <#assign hasAnyImportFields = false>
            <#list po.importFields as field>
                <#if field.modelName == rel.name>
                    <#assign hasAnyImportFields = true>
                    <#break>
                </#if>
            </#list>
            <#if hasAnyImportFields>
        if (CollectionUtils.isNotEmpty(${rel.uncapName}List)) {
            ${rel.uncapName}Mapper.batchAddByJdbc(new BatchInsertParam(${rel.uncapName}List));
        }
            </#if>
        </#list>
        <#list po.relManyList as rel>
            <#assign hasAnyImportFields = false>
            <#list po.importFields as field>
                <#if field.modelName == rel.name>
                    <#assign hasAnyImportFields = true>
                    <#break>
                </#if>
            </#list>
            <#if hasAnyImportFields>
        if (CollectionUtils.isNotEmpty(${rel.uncapName}AllList)) {
            ${rel.uncapName}Mapper.batchAddByJdbc(new BatchInsertParam(${rel.uncapName}AllList));
        }
            </#if>
        </#list>
    }
    </#if>
    </#if>
    <#-- 批量导入 end -->
    </#if>
}
</#if>